#define KEEP_TYPE_MACROS
#include "uid_stack.h"
#undef KEEP_TYPE_MACROS

#include "debug.h"

#include <stdlib.h>

#define NULL_ELEMENT UID_EMPTY
#define NULL_STACK nullUIDStack

#define STACK_NEW_NODE_FUNC makeUIDNode

struct STACK_STRUCT_NAME
{
  STACK_ELEMENT elt;
  STACK_TYPE tail;
};

STACK_TYPE NULL_STACK = (STACK_TYPE) 0;

STACK_TYPE STACK_EMPTY_FUNC(void)
{
  return NULL_STACK;
}

int STACK_EMPTY_PRED(STACK_TYPE stack)
{
  return (stack == NULL_STACK);
}

void STACK_FREE_FUNC(STACK_TYPE stack)
{
  STACK_TYPE n = NULL_STACK;
  while(!STACK_EMPTY_PRED(stack))
    {
      n = stack->tail;
      free(stack);
      stack = n;
    }
}

STACK_TYPE STACK_NEW_NODE_FUNC(STACK_ELEMENT elt)
{
  STACK_TYPE node = (STACK_TYPE) malloc(sizeof(struct STACK_STRUCT_NAME));

  if(!node)
    {
      TRACE("OUT OF MEMORY!");
      return STACK_EMPTY_FUNC();
    }

  node->elt = elt;

  return node;
}

STACK_TYPE STACK_PUSH_FUNC(STACK_ELEMENT elt, STACK_TYPE stack)
{
  STACK_TYPE node = STACK_NEW_NODE_FUNC(elt);
  node->tail = stack;

  return node;
}

STACK_TYPE STACK_POP_FUNC(STACK_ELEMENT* elt, STACK_TYPE stack)
{
  if(STACK_EMPTY_PRED(stack))
    {
      TRACE("Trying to pop from empty stack");
      *elt = NULL_ELEMENT;
    }

  *elt = stack->elt;

  STACK_TYPE t = stack->tail;
  
  free(stack);

  return t;
}

int STACK_SEARCH_FUNC(STACK_ELEMENT elt, STACK_TYPE stack)
{
  while(!STACK_EMPTY_PRED(stack))
    {
      if(stack->elt == elt) return 1;
      stack = stack->tail;
    }

  return 0;
}

STACK_TYPE STACK_REMOVE_FUNC(STACK_ELEMENT elt, STACK_TYPE stack)
{
  if(STACK_EMPTY_PRED(stack)) return 0;
  
  if(stack->elt == elt)
    {
      free(stack);
      return STACK_EMPTY_FUNC();
    }

  STACK_TYPE init = stack;
  STACK_TYPE t = stack->tail;
  while(!STACK_EMPTY_PRED(t))
    {
      if(t->elt == elt) 
	{
	  stack->tail = t->tail;
	  free(t);
	  
	  return init;
	}

      t = stack->tail;
    }

  return init;
}
